Mail Protocol - SMTP

1. 概述

SMTP的全称是Simple Mail Transfer Protocol,即简单邮件传输协议,基于TCP/IP用于发送邮件的协议,目的旨在提供可靠和高效的邮件传输

其出现替代掉了早期同样用于用于邮件传输的FTP协议,SMTP于1981年出现,首份文档为RFC 788 Simple Mail Transfer Protocol,后续经过迭代优化,引入了系列的扩展属性以及登录认证,渐渐地演变成了如今的现代化SMTP协议

2. 架构

当存在用户A向用户B发送一封邮件时,整个发送 & 接收过程如下所示,其中可以看到SMTP主要起到了邮件发送的作用

SMTP

SMTP发送邮件有两个不同的阶段 :submittingrelaying

submitting

客户端发送邮件给邮件服务器(如上图的User A -> User A's Mail server),其端口号一般用的是587,一般需要先通过该端口进行认证,随后再进行发信

这个阶段发送所使用的host一般可直接从邮箱官网 - 设置中获取

relaying

一个邮件服务器投递邮件给另一个邮件服务器,有部分文档也称之为transfer(如上图的User A's Mail server -> User B's Mail server),一般使用的端口是25,其不会进行发件人的身份认证

这个阶段发送所使用的host可以通过获取DNS的MX记录来获取,如下所示可以通过dig来获取指定Mail Server可以发送邮件的host信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
❯ dig thoughtworks.com MX
;; Warning: Message parser reports malformed message packet.

; <<>> DiG 9.10.6 <<>> thoughtworks.com MX
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 46293
;; flags: qr rd ra; QUERY: 1, ANSWER: 5, AUTHORITY: 4, ADDITIONAL: 13
;; WARNING: Message has 5 extra bytes at end

;; QUESTION SECTION:
;thoughtworks.com. IN MX

;; ANSWER SECTION:
thoughtworks.com. 3600 IN MX 5 ALT1.ASPMX.L.GOOGLE.COM.
thoughtworks.com. 3600 IN MX 5 ALT2.ASPMX.L.GOOGLE.COM.
thoughtworks.com. 3600 IN MX 10 ALT4.ASPMX.L.GOOGLE.COM.
thoughtworks.com. 3600 IN MX 10 ALT3.ASPMX.L.GOOGLE.COM.
thoughtworks.com. 3600 IN MX 1 ASPMX.L.GOOGLE.COM.

;; AUTHORITY SECTION:
thoughtworks.com. 286 IN NS sdns58.ultradns.net.
thoughtworks.com. 286 IN NS sdns58.ultradns.biz.
thoughtworks.com. 286 IN NS sdns58.ultradns.org.
thoughtworks.com. 286 IN NS sdns58.ultradns.com.

;; ADDITIONAL SECTION:
alt3.aspmx.l.google.com. 138 IN A 64.233.171.26
alt1.aspmx.l.google.com. 122 IN A 142.250.141.27
alt2.aspmx.l.google.com. 57 IN A 142.250.115.26
aspmx.l.google.com. 118 IN A 64.233.188.26
sdns58.ultradns.org. 80955 IN A 156.154.143.58
sdns58.ultradns.net. 62210 IN A 156.154.141.58
sdns58.ultradns.biz. 62210 IN A 156.154.142.58
sdns58.ultradns.com. 18103 IN A 156.154.140.58
sdns58.ultradns.org. 80955 IN AAAA 2610:a1:1004::3a
sdns58.ultradns.net. 62210 IN AAAA 2610:a1:1002::3a

;; Query time: 149 msec
;; SERVER: 192.168.1.1#53(192.168.1.1)
;; WHEN: Fri Oct 06 14:44:38 CST 2023
;; MSG SIZE rcvd: 512

通过上述的ANSWER SECTION部分中,可以看到对应的MX记录,同时该记录中包含着1, 5, 10等三个不同的优先级,值越小则表示优先级越高,因此在上述结果中ASPMX.L.GOOGLE.COM的优先级是最高的

什么是MX记录?

DNS的MX记录(Mail Exchanger记录)是一种DNS资源记录,用于指定接收电子邮件的邮件服务器,MX记录告诉其他邮件服务器如何将电子邮件发送到特定域名的邮件服务器,在电子邮件系统中,MX记录是非常重要的,因为它们帮助确定电子邮件的路由路径,确保邮件能够正确地投递到接收方的邮箱

什么是Dig?

用于在Linux命令行环境下获取指定域名的DNS信息,可以通过Dig快速教程来熟悉这个命令

3. 端口

  • 25:该端口由RFC 821标准引入,该端口默认不支持SSL并且不用身份认证
  • 465:一般默认SMTP协议是TCP明文传输,如果需要升级为SSL,则一般需要再次协商,如果期望在第一次建立TCP连接就使用SSL加密,则可以使用465端口,该端口设计的初衷就是用于SSL连接,但最终未被采纳
  • 587:该端口在 RFC 2476中定义,需要身份认证

4. 命令

SMTP通过一系列的命令来完成身份认证与邮件的发送

HELO

发送方问候收件方,本质上是英文单词HELLO的缩写,用于建立一次全新的SMTP会话,一般携带的参数是邮件发送端自身的标识

EHLO

其全称是Extended Hello,与HELO相同,都是用于建立一次全新的SMTP会话,但是不一样的是该命令的响应会返回当前邮件接收端支持的扩展特性,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
❯ telnet smtp.163.com 25
Trying 220.181.15.161...
Connected to smtp.163.com.
Escape character is '^]'.
220 163.com Anti-spam GT for Coremail System (163com[20141201])
EHLO zchengb
250-mail
250-PIPELINING
250-AUTH LOGIN PLAIN XOAUTH2
250-AUTH=LOGIN PLAIN XOAUTH2
250-coremail 1Uxr2xKj7kG0xkI17xGrU7I0s8FY2U3Uj8Cz28x1UUUUU7Ic2I0Y2UrLFXTDUCa0xDrUUUUj
250-STARTTLS
250-ID
250 8BITMIME

可以看到在发送完HELO后,邮件接收端返回中携带了一些特性信息,各个特性的解释如下:

250-PIPELINING:表示服务器支持流水线模式,在流水线模式中支持一次性发送多个SMTP命令

250-AUTH LOGIN PLAIN XOAUTH2:这部分列出了服务器支持的身份验证方法,表明服务器支持以下身份验证方法:

  • “LOGIN”:基于用户名和密码的身份验证
  • “PLAIN”:基于明文的身份验证
  • “XOAUTH2”:OAuth 2.0协议的一种身份验证方式,通常用于Google等服务

250-AUTH=LOGIN PLAIN XOAUTH2:与上一行类似,但使用了等号来做分割

250-STARTTLS:服务器支持的另一项特性,它允许SMTP通信升级为加密通信(SSL),以增加安全性

250 8BITMIME:表示服务器支持8位MIME(Multipurpose Internet Mail Extensions),8BITMIME允许电子邮件传输包含8位数据的MIME编码消息,以支持更多字符集和内容类型

其中需要注意的是,SMTP响应中,如果为最后一行,则响应格式则不是[STATUS_CODE]-[TEXT],而是[STATUS_CODE] [TEXT],最后一行不以-作为间隔符

AUTH LOGIN

该命令主要用于登录邮箱账号获得认证,才能够进行后续的邮件发送,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
❯ telnet smtp.163.com 25
Trying 103.74.29.40...
Connected to smtp.163.com.
Escape character is '^]'.
220 163.com Anti-spam GT for Coremail System (163com[20141201])
HELO zchengb
250 OK
auth login
334 dXNlcm5hbWU6
[输入邮箱账号base64加密后的字符串]
334 UGFzc3dvcmQ6
[输入邮箱秘钥base64加密后的字符串]
235 Authentication successful

Tips: Linux下可以通过echo -n "原文" | base64对原文字符串进行base64加密,可以通过echo -n "BASE64密文" | base64 -D进行base64解密

可以看到输入auth login后,服务端的响应是334 dXNlcm5hbWU6,在输入邮箱账号base64字符串回车后,服务端的响应是334 UGFzc3dvcmQ6,对应的通过base64解密可以得知对应两个返回的字符串为:

1
2
3
4
$ echo -n "dXNlcm5hbWU6" | base64 -D
username:
$ echo -n "UGFzc3dvcmQ6" | base64 -D
Password:

MAIL FROM

用于标明发信人的身份,命令的使用如下所示:

1
2
$ MAIL FROM:<zxchengb@163.com>
250 OK

RCPT TO

用于标明收信人的身份信息,具体使用如下所示:

1
2
3
4
$ RCPT TO:<zxchengb@qq.com>
250 OK
$ RCPT TO:<1254412835@qq.com>
250 OK

需要注意的是,在SMTP中无法区分BCC、CC和TO的身份,这一类信息需要在邮件正文的mime header里的不同字段进行区分,该指令同时还会检测邮箱是否存在,如果邮箱不存在,则会返回5xx的状态码

DATA

用于发送方正式发送邮件主体内容数据,如果发送结束,则需要以<CRLF>.<CRLF>作为结束符

QUIT

用于结束当前会话,通知邮件服务器断开连接,如下所示:

1
2
$ QUIT
221 Bye.

RSET

表示清除当前所有缓冲数据,包含发件人、收件人和邮件内容

VRFY

用于验证指定的用户邮箱是否存在,但出于安全问题,大部分情况下都不会提供该命令功能

EXPN

用于验证给定的邮箱列表是否存在,跟VRFY一样,该命令通常会被禁用

HELP

用于查询服务器支持的命令,大部分邮件服务器也会禁用该命令

NOOP

可以理解成是一个心跳请求,接收方如果一切正常则必须回复250 OK


利用以上命令可以在命令行中发送一封邮件,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
❯ telnet smtp.163.com 25
Trying 103.74.29.40...
Connected to smtp.163.com.
Escape character is '^]'.
220 163.com Anti-spam GT for Coremail System (163com[20141201])
HELO zchengb
250 OK
AUTH LOGIN
334 dXNlcm5hbWU6
[邮箱账号base64加密后的字符串]
334 UGFzc3dvcmQ6
[邮箱秘钥base64加密后的字符串]
235 Authentication successful
MAIL FROM:<zxchengb@163.com>
250 Mail OK
RCPT TO:<zxchengb@qq.com>
250 Mail OK
DATA
354 End data with <CR><LF>.<CR><LF>
Subject: This is a Email subject
From: zxchengb@163.com

Hello, I am zchengb. A software engineer from Thoughtworks Inc.
.
250 Mail OK queued as zwqz-smtp-mta-g0-0,_____wDXKIzMyB9l1kAXEA--.48520S2 1696582016

5. 状态码

每次发送命令,服务端都会返回一个状态码,以下是常见的状态码返回清单

Code Desc
211 系统状态或系统帮助响应
214 帮助信息
220 服务就绪
221 服务关闭
250 要求的操作已完成
251 用户非当前邮件服务器,将进行转发
334 等待用户输入验证信息
354 开始邮件输入,以”.”结束
421 服务未就绪,关闭传输通道
450 要求的邮件操作未完成,邮箱不可用
451 放弃要求的操作,处理过程中出错
452 系统存储不足,要求的操作未执行
501 参数格式错误
502 命令不可实现
503 错误的命令序列
504 命令参数不可实现
550 要求的邮件操作未完成,邮箱不可用
551 用户非当前邮件服务器
552 过量的存储分配,要求的操作未完成
553 邮箱名不可用
554 操作失败